#include "FAT32_functions.h"


/*variables globales de las funciones del PdD*/
FILE * ptr;
size_t result;
/*Fin variables globales*/

/*___________________________________________________________________________*/

/****---------------Boot Region---------------****/

int leer_Boot_Sector(){

	char bootSector[512];

	/*Funciones del planificador, a modo de prueba temporal*/

	abrirArchivoDisco();
	leerArchivoDisco(0,bootSector);

	/*Fin funciones del planificador de disco*/

	(FAT32.tamanioSector) =convertirLittleEndianABigEndianEnVector(bootSector+0x0B,2);

	(FAT32.sectoresPorCluster) = bootSector[0x0D]; //little endian no causa efecto en 1byte;

	(FAT32.sectoresReservados) = convertirLittleEndianABigEndianEnVector(bootSector+0x0E,2);

	(FAT32.sectoresPorFAT)=convertirLittleEndianABigEndianEnVector(bootSector+0x24,4);

	(FAT32.numClusterDirRoot)= convertirLittleEndianABigEndianEnVector(bootSector+0x2c,4);

	FAT32.cantidadSectores = convertirLittleEndianABigEndianEnVector(bootSector+0x20,4);

	FAT32.numClustersLibres=0;

	/*Num de Cluster de dirRoot generalmente es 2. Lo mismo que sectores reservados que es
		32. Su cálculo es más que nada para evitar problemas en caso de anomalías.*/

	return 0;
}

/*___________________________________________________________________________*/

/*Seteo los valores que pide el enunciado para el FS Information Sector*/

void setFS(void){

	char buffFS[512];
	uint32_t b= (-1);
	b=(swap_uint32(b));
	leerArchivoDisco(1,buffFS);
	memcpy(buffFS+0x1E8,&b,sizeof(uint32_t));
	memcpy(buffFS+0x1EC,&b,sizeof(uint32_t));
	escribirArchivoDisco(1,buffFS);

	return;
}

/****---------------Boot Region---------------****/

/*___________________________________________________________________________*/

/****---------------FAT Region---------------****/

int bajar_datos_Cluster_FAT(){

	int i,j,num;

	char vector[FAT32.tamanioSector];

	int cantClusterAccedibles = (FAT32.cantidadSectores - FAT32.sectoresReservados-(2*FAT32.sectoresPorFAT))/FAT32.sectoresPorCluster;

	initBitVector(cantClusterAccedibles);

	for(i=FAT32.sectoresReservados,num=0;(i<FAT32.sectoresReservados+FAT32.sectoresPorFAT)&&((num-1)< cantClusterAccedibles );i++){

		leerArchivoDisco(i,vector);

		for(j=0;j<FAT32.tamanioSector;j=j+4,num++){

			if(0x0000000 == convertirLittleEndianABigEndianEnVector(vector+j,4)){
				setSector(num,0);
				FAT32.numClustersLibres++;
			}
			else
				setSector(num,1);
		}
	}
	bajarBitVector();

	return 0;
}
/*___________________________________________________________________________*/

int agregarCluster(int *numeroDeCluster,listaClusters * clusters){


	if(clusters->numCluster==0){

		clusters->numCluster=*numeroDeCluster;
		clusters->sig=NULL;
	}

	else{

		while(clusters->sig!=NULL)
			clusters=clusters->sig;

		clusters->sig=malloc(sizeof(listaClusters));
		clusters->sig->numCluster=*numeroDeCluster;
		clusters->sig->sig=NULL;

	}

	return 0;

}

/*___________________________________________________________________________*/

int buscar_Clusters_libres(int cant_clusters,int*vectorLibres){
int cantClusterAccedibles = (FAT32.cantidadSectores - FAT32.sectoresReservados-(2*FAT32.sectoresPorFAT))/FAT32.sectoresPorCluster;
	/*Se da por hecho que ya se controló la estructura de fat32_data
	 *y que en la misma figura que hay suficientes clusters libres*/

	FILE* clusters;
	int numCluster,valor,cantLibres;
	clusters=fopen("/home/utn_so/free-sectors", "r+");

	/*los clusters guardados incluyen los dos reservados iniciales y al 2.*/

	for(numCluster=0,cantLibres=0;((valor=fgetc(clusters))!=EOF)&&cantLibres<cant_clusters;numCluster++)
		if (valor=='0'){
			vectorLibres[cantLibres]=numCluster;
			cantLibres++;
			setSector(numCluster,1);

		}

	fclose(clusters);

	if(cantLibres<cant_clusters)
		return 1; //estamos al horno. Se corrompió el bitVector.
	else{
		bajarBitVector();
		FAT32.numClustersLibres-=cantLibres;
		return 0;
	}
}

/*___________________________________________________________________________*/

int grabar_FAT(int cluster, int valor){

	int numSector,offset;
	char sector[512];
	if(valor>0xFF/*&&valor==0xffffff8&&valor==0xfffffff*/)
		valor=(swap_uint32(valor));
	offset=calcularSectorPosicionCluster(cluster,&numSector);
	leerArchivoDisco(numSector,sector);
	memcpy(sector+offset,&valor,sizeof(uint32_t));
	escribirArchivoDisco(numSector,sector);
	return 0;
}

/****---------------FAT Region---------------****/

/*___________________________________________________________________________*/

/*Funciones propias del planificador de disco, usadas como
  medio de prueba temporal para testear el funcionamiento
  de la capa FAT.*/

int abrirArchivoDisco()
{
	ptr = fopen("/home/utn_so/fat32.disk6", "r+");
	if(ptr==NULL) return -1;
	else {
		posix_fadvise((int)ptr, 0,0,POSIX_FADV_RANDOM);

		return 0;
	}
}

void leerArchivoDisco(int sector,char* buffLectura)
{
	fseek(ptr,sector*512,SEEK_SET);
	result = fread_unlocked(buffLectura, 1, 512,ptr);
	if(result == (size_t) 512) ;//printf("todo bien\n");
	else printf("todo mal\n");

}

void escribirArchivoDisco(int sector,char* buffEscritura)
{
	fseek(ptr,sector*512,SEEK_SET);
	result = fwrite_unlocked(buffEscritura,1,512,ptr); /*escribe el buffer*/
	if(result == 512) ;//printf("todo bien\n");
	else printf("todo mal");
}


/*Fin de las funciones propias del planificador de disco*/

/*___________________________________________________________________________*/

/****---------------Data Region---------------****/

int leerDirectorio(fat32_directory * directorio,int numCluster){

	listaClusters* cadenaClusters=NULL;
	cadenaClusters=malloc(sizeof(listaClusters));
	cadenaClusters->numCluster=0;
	int tamanioCadena;
	int resultado=1;
//directorio->sig=NULL;
	tamanioCadena = conseguirCadenaClusters(cadenaClusters,numCluster);

	for(;(tamanioCadena>0)&&(resultado!=0);tamanioCadena--){
		resultado=leerSectoresDelCluster(calcularPrimerSectorDelCluster(cadenaClusters->numCluster),directorio);
		printf("%i\n",cadenaClusters->numCluster);
		cadenaClusters=cadenaClusters->sig;
	}
	free(cadenaClusters);
	return 0;
}

/*___________________________________________________________________________*/



/*___________________________________________________________________________*/
int conseguirCadenaClusters(listaClusters* cadenaClusters,int numCluster){
	int numSector;
	int offset;
	char sector[512];
	int numClusterSig;
    int tamanio = 0;

	agregarCluster(&numCluster,cadenaClusters);
	offset=calcularSectorPosicionCluster(numCluster,&numSector);
	leerArchivoDisco(numSector,sector);
	numClusterSig=parsearCluster((sector+offset));
	tamanio++;

	while(numClusterSig!=0){

		agregarCluster(&numClusterSig,cadenaClusters);
		offset=calcularSectorPosicionCluster(numClusterSig,&numSector);
		leerArchivoDisco(numSector,sector);
		numClusterSig=parsearCluster((sector+offset));
		tamanio++;


	}


	return tamanio;
}

/*___________________________________________________________________________*/

int leerSectoresDelCluster(int sectorInicial,fat32_directory * directorio){

	int indice,resultado;
	char sector[512];
    int offsetSector;
	for(indice=0;indice<FAT32.sectoresPorCluster;indice++){
		leerArchivoDisco(sectorInicial+indice,sector);

		for(offsetSector=0;offsetSector<FAT32.tamanioSector;offsetSector+=32){
			resultado= parsearEntradaDirectorio(sector+offsetSector,directorio);
			if(resultado == VACIA)
				return resultado;
			else if(resultado == LFN){
				fat32_directory*ptr=NULL;
				ptr=directorio;
				while(ptr->sig!=NULL)
					ptr=ptr->sig;
				ptr->LongFN=1;
				ptr->numSectorEntrada=sectorInicial+indice;
				ptr->offsetEntrada=offsetSector;
				offsetSector+=32;
				resultado = 1;

			}
else if(resultado==BORRADA)
offsetSector+=32;

		}
	}

	return resultado;
}

/*___________________________________________________________________________*/

int parsearEntradaDirectorio(char* entradaDirectorio,fat32_directory *directorio){

	uint8_t i,entrada;
	int resultado;

	memcpy(&entrada,entradaDirectorio,sizeof(uint8_t));
	if(entrada==0x00)
		resultado = VACIA;
	else if(entrada==0xE5)
		resultado = BORRADA;

	else{
		memcpy(&entrada,entradaDirectorio+11,sizeof(uint8_t));
			if(entrada==0x0F){
				char vectorAux[26];
				resultado =LFN;
				memset(vectorAux,0,26);
				memcpy(vectorAux,entradaDirectorio+1,10);
				memcpy(vectorAux+10,entradaDirectorio+0x0E,12);
				memcpy(vectorAux+22,entradaDirectorio+0x1C,4);

				for(i=1;i<26;i++){
					vectorAux[i]=vectorAux[i+i];
					vectorAux[i+1]=0;
				}
				cargarEntradaDirectorio(entradaDirectorio,directorio,vectorAux);
			}
			else{
				resultado = NORMAL;
				cargarEntradaDirectorio(entradaDirectorio,directorio,NULL);
			}

	}

return resultado;

}

/*___________________________________________________________________________*/

int calcularPrimerSectorDelCluster(int numCluster){

	return (FAT32.sectoresReservados + FAT32.sectoresPorFAT*2 + (numCluster-2)*FAT32.sectoresPorCluster);

}

/*___________________________________________________________________________*/

int calcularSectorPosicionCluster(int numCluster,int* numSector){

	int indice,offset;

	for(indice=0,*numSector=FAT32.sectoresReservados,offset=0;indice<numCluster;indice++){
offset+=4;

		if(offset==512){
			offset=0;
			offset+=4;
			*numSector=*numSector+1;
		}

	}

	return offset;
}

/*___________________________________________________________________________*/

int parsearCluster(char*cluster){

	uint32_t valor=0;
	memcpy(&valor,cluster,sizeof(uint32_t));
if(valor>0xFF&&valor!=0xffffff8&&valor!=0xfffffff&&valor!=0xffffff0f)
	valor=(swap_uint32(valor));


	if (valor == 0xffffff8)
		return 0;
		else if(valor == 0xfffffff )
			return 0;
		else if(valor == 0x0000000)
			return 0;
		else if( valor==0xffffff0f)
			return 0;
	else
		return valor;

}

/*___________________________________________________________________________*/

int cargarEntradaDirectorio(char* entradaDirectorio,fat32_directory* ptr,char*longfilename){

	char vecAux[4];

	if(ptr->tipo==0){


		if(longfilename!=NULL){
			memset(ptr->nombre,0,17);
			strcpy(ptr->nombre,longfilename);

			if((entradaDirectorio[11+32])==0x20)
					ptr->tipo = ARCHIVO;
				else
					ptr->tipo = DIRECTORIO;

			memcpy(vecAux,entradaDirectorio+32+0x1A,2);
			memcpy(vecAux+2,entradaDirectorio+32+0x14,2);
	uint32_t tam=0;
										memcpy(&tam,entradaDirectorio+32+0x1C,4);
if(tam>0xff)
										ptr->tamanio=swap_uint32(tam);
else
ptr->tamanio=tam;
tam=0;
										memcpy(&tam,vecAux,4);
if(tam>0xff)
										ptr->numClusterInicial=swap_uint32(tam);
else
ptr->numClusterInicial=tam;

			ptr->sig = NULL;


		}
		else{



			if (entradaDirectorio[0]==0x2E){
				return 0;

			}
			else{
				memset(ptr->nombre,0,17);
				memcpy(ptr->nombre,entradaDirectorio+32,8);
				memcpy(ptr->nombre+8,".",1);
				memcpy(ptr->nombre+9,entradaDirectorio+8+32,3);
				if((entradaDirectorio[11])==0x20)
					ptr->tipo = ARCHIVO;
				else
					ptr->tipo = DIRECTORIO;
			}

			uint32_t tam=0;
memcpy(vecAux,entradaDirectorio+0x1A,2);
			memcpy(vecAux+2,entradaDirectorio+0x14,2);
										memcpy(&tam,entradaDirectorio+0x1C,4);
if(tam>0xff)
										ptr->tamanio=swap_uint32(tam);
else
ptr->tamanio=tam;
tam=0;
										memcpy(&tam,vecAux,4);
if(tam>0xff)
										ptr->numClusterInicial=swap_uint32(tam);
else
ptr->numClusterInicial=tam;

			ptr->sig = NULL;



		}
	}

	else{

if (entradaDirectorio[0]==0x2E){

				return 0;

			}

		while(ptr->sig!=NULL)
			ptr=ptr->sig;



		if(longfilename!=NULL){
			ptr->sig=malloc(sizeof(fat32_directory));
					memset(ptr->sig->nombre,0,17);
			strcpy(ptr->sig->nombre,longfilename);

			if((entradaDirectorio[11+32])==0x20)
					ptr->sig->tipo = ARCHIVO;
				else
					ptr->sig->tipo = DIRECTORIO;

					memcpy(vecAux,entradaDirectorio+32+0x1A,2);
			memcpy(vecAux+2,entradaDirectorio+32+0x14,2);
	uint32_t tam=0;
										memcpy(&tam,entradaDirectorio+32+0x1C,4);
if(tam>0xff)
										ptr->sig->tamanio=swap_uint32(tam);
else
ptr->sig->tamanio=tam;
tam=0;
										memcpy(&tam,vecAux,4);
if(tam>0xff)
										ptr->sig->numClusterInicial=swap_uint32(tam);
else
ptr->sig->numClusterInicial=tam;

ptr->sig->sig=NULL;




		}
		else{



			
			
				ptr->sig=malloc(sizeof(fat32_directory));
								memset(ptr->sig->nombre,0,17);
				memcpy(ptr->sig->nombre,entradaDirectorio+32,8);
				memcpy(ptr->sig->nombre+8,".",1);
				memcpy(ptr->sig->nombre+9,entradaDirectorio+8+32,3);
				if((entradaDirectorio[11])==0x20)
					ptr->sig->tipo = ARCHIVO;
				else
					ptr->sig->tipo = DIRECTORIO;
			

			uint32_t tam=0;
memcpy(vecAux,entradaDirectorio+0x1A,2);
			memcpy(vecAux+2,entradaDirectorio+0x14,2);
										memcpy(&tam,entradaDirectorio+0x1C,4);
if(tam>0xff)
										ptr->sig->tamanio=swap_uint32(tam);
else
ptr->sig->tamanio=tam;
tam=0;
										memcpy(&tam,vecAux,4);
if(tam>0xff)
										ptr->sig->numClusterInicial=swap_uint32(tam);
else
ptr->sig->numClusterInicial=tam;

			ptr->sig->sig=NULL;



		}



	}

	return 0;

}

/*___________________________________________________________________________*/

uint32_t convertirLittleEndianABigEndianEnVector(char*vector,int tamanioVector){
/*A la inversa: big a endian -NO TESTEADO AUN-*/
	uint32_t valor,i;
	int offset;
	uint32_t resultado= 0x00000000;
	uint32_t mask= 0xFF000000;

	for(i=0;i<tamanioVector/2;i++){
		valor=vector[i];
		vector[i]=vector[tamanioVector-1-i];
		vector[tamanioVector-1-i]=valor;
	}

	switch(tamanioVector){
		case 2:offset=16;break;
		case 4:offset = 0;break;
	}

	for(i=0;i<tamanioVector;i++,offset+=8){
		valor= (swap_uint32((uint32_t)vector[i]))>>offset;
		resultado=	resultado |(valor&(mask>>offset));
	}

	return resultado;
}

/*___________________________________________________________________________*/

int buscarEntradaLibre(int numCluster,int* sectorIni,int*offset){
	fat32_directory*  directorio=malloc(sizeof(fat32_directory));
	listaClusters* cadenaClusters=NULL;
	cadenaClusters=malloc(sizeof(listaClusters));
	cadenaClusters->numCluster=0;
	int tamanioCadena;
	int resultado=1;
	int sectorInicial;
	int indice;
	char sector[512];
	int offsetSector;
	tamanioCadena = conseguirCadenaClusters(cadenaClusters,numCluster);
	directorio->tipo=0;
	for(;(tamanioCadena>0)&&(resultado!=0);tamanioCadena--){
		sectorInicial=calcularPrimerSectorDelCluster(cadenaClusters->numCluster);
		cadenaClusters=cadenaClusters->sig;
		{

			for(indice=0;indice<FAT32.sectoresPorCluster;indice++){
				if((resultado == VACIA) || (resultado==BORRADA)){
					free(directorio);free(cadenaClusters);
												*sectorIni=sectorInicial+indice;
												*offset=offsetSector;
											 return 0;

				}

				leerArchivoDisco(sectorInicial+indice,sector);

				for(offsetSector=0;offsetSector<FAT32.tamanioSector;offsetSector+=32){
					resultado= parsearEntradaDirectorio(sector+offsetSector,directorio);
					if((resultado == VACIA) || (resultado==BORRADA)){
						free(directorio);free(cadenaClusters);
							*sectorIni=sectorInicial+indice;
							*offset=offsetSector;
						 return 0;
					}
					else if(resultado == LFN){
fat32_directory*ptr=NULL;
ptr=directorio;
				while(ptr->sig!=NULL)
					ptr=ptr->sig;
						ptr->LongFN=1;
						ptr->numSectorEntrada=sectorInicial+indice;
						ptr->offsetEntrada=offsetSector;
						offsetSector+=32;
						resultado = 1;
					}


				}
			}
		}

		
	}



	return 0;
}
